using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;


namespace Ext.Net.UIS.Script
{
    public static class ScriptTermHelper
    {
        public static void CheckProperty(ConstantExpression term, string propName)
        {
            if (term.Type != typeof(ScriptTerm))
                throw new InvalidExpressionException("UIS.TermScript: can't get term-property '" + propName + "' from constant of type " + term.Type.Name);
        }

        // ReSharper disable PossiblyMistakenUseOfParamsMethod


        #region Enabled

        private static readonly PropertyInfo EnabledInfo = typeof(ScriptTerm).GetProperty("Enabled");

        public static Expression Enabled(this ConstantExpression term)
        {
            CheckProperty(term, "Enabled");
            return Expression.Property(term, EnabledInfo);
        }

        public static Expression SetEnabled(this ConstantExpression term, Expression value = null)
        {
            CheckProperty(term, "SetEnabled");
            return Expression.Assign(term.Enabled(), value ?? TermScript.Value);
            //return Expression.Call(term, SetEnabledInfo, value ?? TermScript.Value);
        }

        #region Enabled Extentions

        public static Expression Enabled(this ScriptTerm term)
        {
            return Enabled((ConstantExpression)term);
        }

        public static Expression Enabled(this string termName)
        {
            return Enabled(new ScriptTerm(termName));
        }


        public static Expression SetEnabled(this ConstantExpression term, bool value)
        {
            return term.SetEnabled(Expression.Constant(value));
        }
        public static Expression SetEnabled(this ConstantExpression term, Expression<Func<bool>> value)
        {
            return term.SetEnabled((Expression)value);
        }
        public static Expression BindEnabled(this ConstantExpression term, string value)
        {
            return term.SetEnabled(new ScriptTerm(value).Value());
        }


        public static Expression SetEnabled(this string termName, Expression value = null)
        {
            return SetEnabled(new ScriptTerm(termName), value ?? TermScript.Value);
        }
        public static Expression SetEnabled(this string termName, bool value)
        {
            return termName.SetEnabled(Expression.Constant(value));
        }
        public static Expression SetEnabled(this string termName, Expression<Func<bool>> value)
        {
            return termName.SetEnabled((Expression)value);
        }
        public static Expression BindEnabled(this string termName, string value)
        {
            return termName.SetEnabled(new ScriptTerm(value).Value());
        }


        public static Expression SetEnabled(this string[] termNames, Expression value = null)
        {
            value = value ?? TermScript.Value;
            return Expression.Block(typeof(void),
                termNames.Select(termName => termName.SetEnabled(value))
            );
        }
        public static Expression SetEnabled(this string[] termNames, bool value)
        {
            return termNames.SetEnabled(Expression.Constant(value));
        }
        public static Expression SetEnabled(this string[] termNames, Expression<Func<bool>> value)
        {
            return termNames.SetEnabled((Expression)value);
        }
        public static Expression BindEnabled(this string[] termNames, string value)
        {
            return termNames.SetEnabled(new ScriptTerm(value).Value());
        }

        #endregion

        #endregion


        #region Value

        private static readonly PropertyInfo ValueInfo = typeof(ScriptTerm).GetProperty("Value");

        public static Expression Value(this ConstantExpression term)
        {
            CheckProperty(term, "Value");
            return Expression.Property(term, ValueInfo);
        }

        public static Expression SetValue(this ConstantExpression term, Expression value = null)
        {
            CheckProperty(term, "SetValue");
            return Expression.Assign(term.Value(), value ?? TermScript.Value);
        }

        #region Value Extentions

        public static Expression Value(this ScriptTerm term)
        {
            return Value((ConstantExpression)term);
        }

        public static Expression Value(this string termName)
        {
            return Value(new ScriptTerm(termName));
        }


        public static Expression SetValue(this ConstantExpression term, object value)
        {
            return term.SetValue(Expression.Constant(value));
        }
        public static Expression SetValue(this ConstantExpression term, Expression<Func<object>> value)
        {
            return term.SetValue((Expression)value);
        }
        public static Expression BindValue(this ConstantExpression term, string value)
        {
            return term.SetValue(new ScriptTerm(value).Value());
        }


        public static Expression SetValue(this string termName, Expression value = null)
        {
            return SetValue(new ScriptTerm(termName), value ?? TermScript.Value);
        }
        public static Expression SetValue(this string termName, object value)
        {
            return termName.SetValue(Expression.Constant(value));
        }
        public static Expression SetValue(this string termName, Expression<Func<object>> value)
        {
            return termName.SetValue(value != null ? value.Body : null);
        }
        public static Expression BindValue(this string termName, string value)
        {
            return termName.SetValue(new ScriptTerm(value).Value());
        }

        #endregion

        #endregion


        // ReSharper restore PossiblyMistakenUseOfParamsMethod


    }
}